﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
namespace PPIDE
{
    public class InfoStruct
    {
        public InfoStruct(string name, int val)
        {
            Name = name;
            Val = val;
        }
        public string Name;
        public int Val;
    }
    class PpCompiler
    {
       
        #region defines
        //Instructions Group
        public static readonly InfoStruct GROUP_MOV = new InfoStruct("GROUP_MOV", 0x02);
        public static readonly InfoStruct GROUP_OP = new InfoStruct("GROUP_OP", 0x03);
        public  static readonly InfoStruct GROUP_JMP = new InfoStruct("GROUP_JMP", 0x05);
        //Instruction Type
        public  static readonly InfoStruct NORM_INS = new InfoStruct("NORM_INS", 0x00);
        public  static readonly InfoStruct PP_INS = new InfoStruct("PP_INS", 0x01);

        //Instruction 
        public static readonly InfoStruct HALT = new InfoStruct("HALT", 0x00);
        public  static readonly InfoStruct NOP = new InfoStruct("NOP", 0x10);
        public  static readonly InfoStruct IRMOV16 = new InfoStruct("IRMOV16", 0x20);
        public  static readonly InfoStruct RMMOV16 = new InfoStruct("RMMOV16", 0x21);
        public  static readonly InfoStruct RMMOV32 = new InfoStruct("RMMOV32", 0x22);
        public  static readonly InfoStruct MRMOV16 = new InfoStruct("MRMOV16", 0x23);
        public  static readonly InfoStruct MRMOV32 = new InfoStruct("MRMOV32", 0x24);
        public  static readonly InfoStruct RRMOV16 = new InfoStruct("RRMOV16", 0x25);
        public  static readonly InfoStruct RRMOV32 = new InfoStruct("RRMOV32", 0x26);

        public  static readonly InfoStruct ADD = new InfoStruct("ADD", 0x30);
        public  static readonly InfoStruct SUB = new InfoStruct("SUB", 0x31);
        public  static readonly InfoStruct MULT = new InfoStruct("MULT", 0x32);

        public  static readonly InfoStruct RET = new InfoStruct("RET", 0x40);
        public  static readonly InfoStruct CALL = new InfoStruct("CALL", 0x41);
        public  static readonly InfoStruct PUSH = new InfoStruct("PUSH", 0x42);
        public  static readonly InfoStruct POP = new InfoStruct("POP", 0x43);

        public  static readonly InfoStruct JMP = new InfoStruct("JMP", 0x50);
        public  static readonly InfoStruct JMPLE = new InfoStruct("JMPLE", 0x51);
        public  static readonly InfoStruct JMPL = new InfoStruct("JMPL", 0x52);
        public  static readonly InfoStruct JMPE = new InfoStruct("JMPE", 0x53);
        public  static readonly InfoStruct JMPNE = new InfoStruct("JMPNE", 0x54);
        public  static readonly InfoStruct JMPGE = new InfoStruct("JMPGE", 0x55);
        public  static readonly InfoStruct JMPG = new InfoStruct("JMPG", 0x56);

        public  static readonly InfoStruct BUB = new InfoStruct("BUB", 0x7F);
        public static readonly InfoStruct STARTPP = new InfoStruct("STARTPP", 0x01);
        public static InfoStruct[] INS = { HALT, NOP, IRMOV16, RMMOV16, RMMOV32, MRMOV16, MRMOV32, RRMOV16, RRMOV32, ADD, SUB, MULT, RET, CALL, PUSH, POP ,
                                                    JMP, JMPLE,JMPL,JMPE,JMPNE,JMPGE,JMPG,STARTPP};
        //conditions
        public  static readonly InfoStruct CND_YES = new InfoStruct("CND_YES", 0x0);
        public  static readonly InfoStruct CND_LE = new InfoStruct("CND_LE", 0x1);
        public  static readonly InfoStruct CND_L = new InfoStruct("CND_L", 0x2); // < 
        public  static readonly InfoStruct CND_E = new InfoStruct("CND_E", 0x3); //= new InfoStruct("",= new InfoStruct("", 
        public  static readonly InfoStruct CND_NE = new InfoStruct("CND_NE", 0x4); // != new InfoStruct("", 
        public  static readonly InfoStruct CND_GE = new InfoStruct("CND_GE", 0x5); // >= new InfoStruct("", 
        public  static readonly InfoStruct CND_G = new InfoStruct("CND_G", 0x6); // >

        //status
        public  static readonly InfoStruct ST_AOK = new InfoStruct("ST_AOK", 0x0);
        public  static readonly InfoStruct ST_HLT = new InfoStruct("ST_HLT", 0x1);
        public  static readonly InfoStruct ST_ADR = new InfoStruct("ST_ADR", 0x2);
        public  static readonly InfoStruct ST_INS = new InfoStruct("ST_INS", 0x3);

        //regs
        public  static readonly InfoStruct R0 = new InfoStruct("R0", 0x0);
        public  static readonly InfoStruct R1 = new InfoStruct("R1", 0x1);
        public  static readonly InfoStruct RSP = new InfoStruct("RSP", 0x1);//stack pointer ,also named R1
        public  static readonly InfoStruct R2 = new InfoStruct("R2", 0x2);
        public  static readonly InfoStruct R3 = new InfoStruct("R3", 0x3);
        public  static readonly InfoStruct R4 = new InfoStruct("R4", 0x4);
        public  static readonly InfoStruct R5 = new InfoStruct("R5", 0x5);
        public  static readonly InfoStruct R6 = new InfoStruct("R6", 0x6);
        public  static readonly InfoStruct R7 = new InfoStruct("R7", 0x7);
        public  static readonly InfoStruct RNULL = new InfoStruct("RNULL", 0xF);
        public static  InfoStruct[] REGS = { R0, R1, R2, R3, R4, R5, R6, R7, RSP, RNULL };
        #endregion

        private static bool findInfo(string name, ref InfoStruct[] array,out int indx)
        {
            indx = 0;
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i].Name == name)
                {
                    indx = i;
                    return true;
                }
            }
            return false;
        }
        private static Int32 composeInstrMachineCode(InfoStruct Instr, bool is_PP_Ins, InfoStruct Ra, InfoStruct Rb, InfoStruct Rc,Int16 Imm)
        {
            Int32 instr_code = HALT.Val << 24;
            switch (Instr.Name)
            {
                case "HALT": instr_code = HALT.Val << 24 ; break;
                case "NOP": instr_code = NOP.Val<<24; break;
                case "IRMOV16": instr_code =( IRMOV16.Val<<24)| (Rb.Val<<16)|(Imm&0x0000FFFF); break;
                case "RMMOV16": instr_code = (RMMOV16.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Imm & 0x0000FFFF); break;
                case "RMMOV32": instr_code = (RMMOV32.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Imm & 0x0000FFFF); break;
                case "MRMOV16": instr_code = (MRMOV16.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Imm & 0x0000FFFF); break;
                case "MRMOV32": instr_code = (MRMOV32.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Imm & 0x0000FFFF); break;
                case "RRMOV16": instr_code = (RRMOV16.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16); break;
                case "RRMOV32": instr_code = (RRMOV32.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16); break;

                case "ADD": instr_code = (ADD.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Rc.Val << 12); break;
                case "SUB": instr_code = (SUB.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Rc.Val << 12); break;
                case "MULT": instr_code = (MULT.Val<<24) | (Ra.Val << 20) | (Rb.Val << 16) | (Rc.Val << 12); break;

                case "RET": instr_code = RET.Val << 24; break;
                case "CALL": instr_code = CALL.Val << 24 | (Imm & 0x0000FFFF); break;
                case "PUSH": instr_code = PUSH.Val << 24 | (Ra.Val << 20); break;
                case "POP": instr_code = POP.Val << 24 | (Rb.Val << 16); break;

                case "JMP": instr_code = JMP.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPLE": instr_code = JMPLE.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPL": instr_code = JMPL.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPE": instr_code = JMPE.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPNE": instr_code = JMPNE.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPGE": instr_code = JMPGE.Val << 24 | (Imm & 0x0000FFFF); break;
                case "JMPG": instr_code = JMPG.Val << 24 | (Imm & 0x0000FFFF); break;

                case "STARTPP": instr_code = STARTPP.Val << 24 | (Imm & 0x0000FFFF); break;
                case "BUB": instr_code = BUB.Val << 24; break;
                default: instr_code = HALT.Val << 24; break;                    
            }
            return is_PP_Ins ? (int)(instr_code|0x80000000):instr_code ;
        }
        private static Int16 translateImm(string str_Imm)
        {
            Int16 Imm = 0;
            //translate Imm
            if (str_Imm[str_Imm.Length - 1] == 'd')
            {
                Imm = Int16.Parse(str_Imm.Substring(0, str_Imm.Length - 1));
            }
            else if (str_Imm[str_Imm.Length - 1] == 'h' | str_Imm[str_Imm.Length - 1] == 'H')
            {
                Imm = Int16.Parse(str_Imm.Substring(0, str_Imm.Length - 1), System.Globalization.NumberStyles.HexNumber);
            }
            else
            {
                Imm = Int16.Parse(str_Imm);
            }
            return Imm;
        }
        private static Int32 composeInstrMachineCode_fmt_1_2(string str_cmd, bool is_PP_instr, string str_Ra, string str_Rb, string str_Imm,int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
            int Ra_indx;
            found = findInfo(str_Ra, ref REGS, out Ra_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Ra));
            }
            int Rb_indx;
            found = findInfo(str_Rb, ref REGS, out Rb_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Rb));
            }
            
            Int16 Imm = translateImm(str_Imm);

            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, REGS[Ra_indx], REGS[Rb_indx], null, Imm);
        }
        private static Int32 composeInstrMachineCode_fmt_3(string str_cmd, bool is_PP_instr, string str_Ra, string str_Rb, string str_Rc, int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
            int Ra_indx;
            found = findInfo(str_Ra, ref REGS, out Ra_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Ra));
            }
            int Rb_indx;
            found = findInfo(str_Rb, ref REGS, out Rb_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Rb));
            }
            int Rc_indx;
            found = findInfo(str_Rc, ref REGS, out Rc_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Rc));
            }
            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, REGS[Ra_indx], REGS[Rb_indx], REGS[Rc_indx], 0);
        }
        private static Int32 composeInstrMachineCode_fmt_4_7(string str_cmd, bool is_PP_instr, string str_Ra, string str_Rb, int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
            int Ra_indx;
            found = findInfo(str_Ra, ref REGS, out Ra_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Ra));
            }
            int Rb_indx;
            found = findInfo(str_Rb, ref REGS, out Rb_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Rb));
            }
         
            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, REGS[Ra_indx], REGS[Rb_indx], null, 0);
        }
        private static Int32 composeInstrMachineCode_fmt_5(string str_cmd, bool is_PP_instr, string str_Rb, string str_Imm, int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
           
            int Rb_indx;
            found = findInfo(str_Rb, ref REGS, out Rb_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize Reg-> {1}\n", line_num, str_Rb));
            }

            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, null, REGS[Rb_indx], null, translateImm(str_Imm));
        }
        private static Int32 composeInstrMachineCode_fmt_6(string str_cmd, bool is_PP_instr, string str_Imm, int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, null, null, null, translateImm(str_Imm));
        }
        private static Int32 composeInstrMachineCode_fmt_8(string str_cmd, bool is_PP_instr,  int line_num)
        {
            int cmd_indx;
            bool found = findInfo(str_cmd, ref INS, out cmd_indx);
            if (!found)
            {
                throw new Exception(string.Format("Error in Line {0} : unrecgonize instr-> {1}\n", line_num, str_cmd));
            }
            return composeInstrMachineCode(INS[cmd_indx], is_PP_instr, null, null, null, 0);
        }
        private static Int32 translateFormat1(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+R\\w+\\s*,\\s*\\d+[DHO]?\\s*\\(\\s*R\\w+\\s*\\)";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Ra, str_Rb, str_Imm;
                //extract cmd
                pattern = "\\w+(?=\\s+R\\w+\\s*,\\s*\\d+[DH]?\\s*\\(\\s*R\\w+\\s*\\))";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                pattern = "(?<=\\w+\\s+)R\\w+(?=\\s*,\\s*\\d+[DH]?\\s*\\(\\s*R\\w+\\s*\\))";
                str_Ra = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                pattern = "(?<=\\w+\\s+R\\w+\\s*,\\s*)\\d+[DH]?(?=\\s*\\(\\s*R\\w+\\s*\\))";
                str_Imm = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value;
                pattern = "(?<=\\w+\\s+R\\w+\\s*,\\s*\\d+[DH]?\\s*\\(\\s*)R\\w+(?=\\s*\\))";
                str_Rb = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != RMMOV16.Name && str_cmd != RMMOV32.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_1_2(str_cmd, is_PP_instr, str_Ra, str_Rb, str_Imm, line_num);                
            }
            return -1;
        }
        private static Int32 translateFormat2(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+\\d+[DHO]?\\s*\\(\\s*R\\w+\\s*\\)\\s*,\\s*R\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Ra, str_Rb, str_Imm;
                //extract cmd
                pattern = "\\w+(?=\\s+\\d+[DHO]?\\s*\\(\\s*R\\w+\\s*\\)\\s*,\\s*R\\w+)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Imm
                pattern="(?<=\\w+\\s+)\\d+[DHO]?(?=\\s*\\(\\s*R\\w+\\s*\\)\\s*,\\s*R\\w+)";
                str_Imm = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value;
                //Ra
                pattern="(?<=\\w+\\s+\\d+[DHO]?\\s*\\(\\s*)R\\w+(?=\\s*\\)\\s*,\\s*R\\w+)";
                str_Ra = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Rb
                pattern = "(?<=\\w+\\s+\\d+[DHO]?\\s*\\(\\s*R\\w+\\s*\\)\\s*,\\s*)R\\w+";
                str_Rb = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();

                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != MRMOV16.Name && str_cmd != MRMOV32.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_1_2(str_cmd, is_PP_instr, str_Ra, str_Rb, str_Imm,line_num);             
            }
            return -1;
        }
        private static Int32 translateFormat3(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+R\\w+\\s*,\\s*R\\w+\\s*,\\s*R\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Ra, str_Rb, str_Rc;
                //extract cmd
                pattern = "\\w+(?=\\s+R\\w+\\s*,\\s*R\\w+\\s*,\\s*R\\w+)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Ra
                pattern = "(?<=\\w+\\s+)R\\w+(?=\\s*,\\s*R\\w+\\s*,\\s*R\\w+)";
                str_Ra = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Rb
                pattern = "(?<=\\w+\\s+R\\w+\\s*,\\s*)R\\w+(?=\\s*,\\s*R\\w+)";
                str_Rb = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Rc
                pattern = "(?<=\\w+\\s+R\\w+\\s*,\\s*R\\w+\\s*,\\s*)R\\w+";
                str_Rc = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != ADD.Name && str_cmd != SUB.Name && str_cmd != MULT.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_3(str_cmd, is_PP_instr, str_Ra, str_Rb, str_Rc,line_num); 
            }
            return -1;
        }
        private static Int32 translateFormat4(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+R\\w+\\s*,\\s*R\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Ra, str_Rb;
                //extract cmd
                pattern = "\\w+(?=\\s+R\\w+\\s*,\\s*R\\w+)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Ra
                pattern = "(?<=\\w+\\s+)R\\w+(?=\\s*,\\s*R\\w+)";
                str_Ra = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Rb
                pattern = "(?<=\\w+\\s+R\\w+\\s*,\\s*)R\\w+";
                str_Rb = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != RRMOV16.Name && str_cmd != RRMOV32.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_4_7(str_cmd, is_PP_instr, str_Ra, str_Rb, line_num);
            }
            return -1;
        }
        private static Int32 translateFormat5(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+\\d+[dh]?\\s*,\\s*R\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Rb, str_Imm;
                //extract cmd
                pattern = "\\w+(?=\\s+\\d+[dh]?\\s*,\\s*R\\w+)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //str_Imm
                pattern = "(?<=\\w+\\s+)\\d+[dh]?(?=\\s*,\\s*R\\w+)";
                str_Imm = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value;
                //Rb
                pattern = "(?<=\\w+\\s+\\d+[dh]?\\s*,\\s*)R\\w+";
                str_Rb = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != IRMOV16.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_5(str_cmd, is_PP_instr, str_Rb, str_Imm,line_num);
            }
            return -1;
        }
        private static Int32 translateFormat6(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+\\d+[dh]?";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Imm;
                //extract cmd
                pattern = "\\w+(?=\\s+\\d+[dh]?)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //str_Imm
                pattern = "(?<=\\w+\\s+)\\d+[dh]?";
                str_Imm = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value;
               
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != JMP.Name && str_cmd!=JMPE.Name &&str_cmd!=JMPG.Name
                    &&str_cmd!=JMPGE.Name && str_cmd!=JMPL.Name && str_cmd!=JMPLE.Name
                    && str_cmd != JMPNE.Name && str_cmd != CALL.Name
                    && str_cmd!=STARTPP.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_6(str_cmd, is_PP_instr, str_Imm, line_num);
            }
            return -1;
        }
        private static Int32 translateFormat7(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+\\s+R\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd, str_Ra;
                //extract cmd
                pattern = "\\w+(?=\\s+R\\w+)";
                str_cmd = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //Ra
                pattern = "(?<=\\w+\\s+)R\\w+";
                str_Ra = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase).Value.ToUpper();
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != PUSH.Name && str_cmd != POP.Name)
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_4_7(str_cmd, is_PP_instr, str_Ra, str_Ra, line_num);
            }
            return -1;
        }
        private static Int32 translateFormat8(string asmline, bool is_PP_instr, int line_num)
        {
            string pattern = "\\w+";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            if (match.Value != string.Empty)
            {
                //there should not be any other charaters left.
                if (match.Value.Length != asmline.Length)
                {
                    throw new Exception(string.Format("Error in Line {0} : syntax-> {1}\n", line_num, asmline.Substring(match.Value.Length)));
                }
                string str_cmd = match.Value.ToUpper();
                
                //this format can only be used by certain instrs,so we check it here.
                if (str_cmd != HALT.Name && str_cmd != NOP.Name && str_cmd != RET.Name
                    && str_cmd != BUB.Name )
                {
                    throw new Exception(string.Format("Error in Line {0} : unmatched instr format-> {1}\n", line_num, str_cmd));
                }
                return composeInstrMachineCode_fmt_8(str_cmd, is_PP_instr, line_num);
            }
            return -1;
        }
        private static void clearCommentsAndTrim(ref string asmline)
        {
            int indx = asmline.IndexOf('#');
            if (indx >0)
            {
                asmline=asmline.Substring(0, indx).Trim();
            }
            else if (indx == 0)
            {
                asmline = string.Empty;
            }
        }
        private static bool IsReservedName(string name)
        {
            name=name.Trim().ToUpper();
            for (int i = 0; i < INS.Length; i++)
            {
                if (name == INS[i].Name)
                    return true;
            }
            for (int i = 0; i < REGS.Length; i++)
            {
                if (name == REGS[i].Name)
                    return true;
            }
            return false;
        }
        private static string extractLabel(ref string asmline,int line_num)
        {
            //we treat asmline as a trimmed string here
            string pattern = "\\w+(?=\\s*:)";
            Match match = Regex.Match(asmline, pattern, RegexOptions.IgnoreCase);
            string labelname = match.Value;
            int indx = asmline.IndexOf(':');
            if (indx > 0)
            {
                asmline = asmline.Substring(indx+1);
            }
            else if (indx == 0)
            {
                throw new Exception(string.Format("Error in Line {0} : no label but only a comma \n", line_num));
            }
            return match.Value;
        }
        /// <summary>
        /// 将一行汇编代码翻译为机器码
        /// </summary>
        /// <param name="asmline">汇编代码行</param>
        /// <param name="line_num">当前行序号</param>
        /// <returns>机器码</returns>
        public static Int32 TranslateAsmLine(ref string asmline,int line_num)
        {
            //possible ins format(label、comment cleared, and blank line also cleared)：
            //Notice there may be more than one legal spaces in some positions.
            //1.cmd Ra , Imm( Rb )
            //2.cmd Imm(Ra),Rb
            //3.cmd Ra,Rb,Rc
            //4. cmd Ra,Rb
            //5. cmd Imm,Ra
            //6.cmd Imm //(jmpxx,call)
            //7.cmd RA  [or]  cmd rB //(push,pop)
            //8.cmd          //(bub,ret,halt,nop)
            asmline = asmline.Trim();
            bool is_PP_instr=asmline[0]=='@'?true:false;
            if(is_PP_instr)
            {
                asmline=asmline.Substring(1).TrimStart();
            }
            Int32 instr_code= translateFormat1(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat2(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat3(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat4(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat5(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat6(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat7(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }
            instr_code = translateFormat8(asmline, is_PP_instr, line_num);
            if (instr_code != -1)
            {
                return instr_code;
            }

            throw new Exception(string.Format("Error in Line {0} : unable to parse this line:{1}\n",line_num,asmline));
            return 0;
        }
        private static byte[] convertInt32ToBigEndianBytes(int i32)
        {
            //i32=0x01234567
            byte[] bs = BitConverter.GetBytes(i32);
            //bytes order now:67,45,23,01
            byte btmp = bs[0];
            bs[0] = bs[3];
            bs[3] = btmp;
            btmp = bs[1];
            bs[1] = bs[2];
            bs[2] = btmp;
            //now the bytes order is :01,23,45,67
            return bs;
        }
        private static void replaceLabelRefs(ref string line,ref ArrayList labels)
        {
            foreach (InfoStruct labelinfo in labels)
            {
                line=line.Replace(labelinfo.Name, labelinfo.Val.ToString("X") + "H");                
            }
        }
        public static byte[] TranslateAsmLines(ref string [] lines)
        {
            ArrayList codebytes = new ArrayList();
            if(lines.Length==0)
            {
                throw new Exception("Error: Empty file");
            }
            
            string labelname_tmp=string.Empty;
            for (int i = 0; i < lines.Length; i++)
            {
                clearCommentsAndTrim(ref lines[i]);              
            }
  
            ArrayList labels = new ArrayList();
            ArrayList compactLineNums = new ArrayList();
            for (int i = 0; i < lines.Length; i++)
            {
                if (lines[i] == string.Empty)
                {
                    continue;
                }
                else if (lines[i][lines[i].Length - 1] == ':')//only a label in this line
                {
                    if ((i + 1) < lines.Length)
                    {
                        lines[i + 1] = lines[i] + lines[i + 1];
                        lines[i] = string.Empty;
                    }
                    else//the last line is a label,this case is illegal
                        throw new Exception();
                }
                else
                {
                    compactLineNums.Add(i);
                }
            }
            for (int i = 0; i < compactLineNums.Count;i++ )
            {
                int k = (int)compactLineNums[i];
                labelname_tmp = extractLabel(ref lines[k], k + 1);
                if (labelname_tmp != string.Empty)
                {
                    if (IsReservedName(labelname_tmp))
                    {
                        throw new Exception(string.Format("Error in Line {0} : you should not use this as a labelname since it is a reserved word:{1}\n", i + 1, labelname_tmp));
                    }
                    else
                    {
                        //InfoStruct labelInfo = new InfoStruct(labelname_tmp, i*4);//如果offset是以字节为单位，则这里地址需要是i*4
                        InfoStruct labelInfo = new InfoStruct(labelname_tmp, i );//这里我们采用RISC 32 ISA，offset可简化为32bit对齐，即offset以4字节为单位，所以不需要乘4
                        labels.Add(labelInfo);
                    }
                }
            }
            for (int i = 0; i < compactLineNums.Count; i++)
            {
                int k = (int)compactLineNums[i];
                 replaceLabelRefs(ref lines[k], ref labels);
                 byte[] line_code =convertInt32ToBigEndianBytes( TranslateAsmLine(ref lines[k], k + 1));
                 codebytes.AddRange(line_code);
            }
            return (byte[])codebytes.ToArray(typeof(byte));
        }
        public static void WriteBinFile(ref byte[] codebytes,string filepath)
        {
            BinaryWriter bw;
            FileStream fs = new FileStream(filepath, FileMode.Create);
            
            bw = new BinaryWriter(fs);
            bw.Write(codebytes);
            bw.Close();
            fs.Close();
        }
        public static void WriteHdlSimMemBankFile(ref byte[] codebytes, string filepath)
        {
            if (filepath[filepath.Length - 1] != '\\' || filepath[filepath.Length - 1] != '/')
                filepath += "/";
            for (int i = 0; i < 8; i++)
            {
                FileStream fs = new FileStream(filepath+"bank"+i+".data", FileMode.Create);
                StreamWriter sw = new StreamWriter(fs);
                for (int j = 0; j < 4096;j+=8 )
                      sw.WriteLine((j<codebytes.Length)?codebytes[j].ToString("X2"):"00");
                    
                sw.Close();
                fs.Close();
            }
        }

    }
}
